//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////


#include "precomp.h"
#include <simtkit.h>

// Macros to round values to DWORD boundaries and add them
#define ROUNDTODWORD2(a, b)          (ROUNDTODWORD(a) + ROUNDTODWORD(b))
#define ROUNDTODWORD3(a, b, c)       (ROUNDTODWORD2(a, b) + ROUNDTODWORD(c))
#define ROUNDTODWORD4(a, b, c, d)    (ROUNDTODWORD2(a, b) + ROUNDTODWORD2(c, d))

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseRefresh(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails;
RILSIMTOOLKITCMD*  pSatCmd;
SIMFILEREFRESH*    pSatRefresh;
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_REFRESH);

  // Parse: "<details>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp) ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatRefresh = (SIMFILEREFRESH*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatRefresh->dwParams     = SIM_PARAM_FILEREFRESH_FLAGS;
    pSatRefresh->dwFlags      = 0;
    switch (nDetails) {
      case 0:
      case 1:
        pSatRefresh->dwFlags  = SIMFILE_FULLFILECHANGE;
        break;
      case 2:
        pSatRefresh->dwFlags  = SIMFILE_SIMINIT | SIMFILE_FULLFILECHANGE;
        break;
      case 3:
        pSatRefresh->dwFlags  = SIMFILE_SIMINIT;
        break;
      case 4:
        pSatRefresh->dwFlags  = SIMFILE_SIMRESET;
        // In case off a full SIM reset the module doesn't require any response
        m_fNoResponse = TRUE;
        break;
      default:
        PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_COMMANDDATA);
        fRet = FALSE;
        break;
    }
    pSatRefresh->cbSize        = ROUNDTODWORD(sizeof(SIMFILEREFRESH));

    pSatCmd->cbSize += pSatRefresh->cbSize;
    pSatCmd->dwDetailsSize = pSatRefresh->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSetupEventList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nEventList;
RILSIMTOOLKITCMD*  pSatCmd;
SIMEVENTLIST*      pSatEventList;
BYTE*              pEvents;
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_EVENTLIST);

  // Parse: "<details>,<eventlist>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)        ||
      !ParseUInt(szRsp, FALSE, nEventList, szRsp)  ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatEventList = (SIMEVENTLIST*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatEventList->dwParams        = SIM_PARAM_SIMEVENTLIST_ALL;
    pSatEventList->dwEventsSize    = 0;
    pSatEventList->dwEventsOffset  = ROUNDTODWORD(sizeof(SIMEVENTLIST));

    pEvents = (BYTE*)pSatEventList + pSatEventList->dwEventsOffset;
    if (nEventList & 0x0010) { pEvents[pSatEventList->dwEventsSize++] = SIMTKIT_EVENT_USERACTIVITY; }
    if (nEventList & 0x0020) { pEvents[pSatEventList->dwEventsSize++] = SIMTKIT_EVENT_IDLESCREEN; }
    if (nEventList & 0x0100) { pEvents[pSatEventList->dwEventsSize++] = SIMTKIT_EVENT_LANGUAGESELECTION; }
    if (nEventList & 0x0200) { pEvents[pSatEventList->dwEventsSize++] = SIMTKIT_EVENT_BROWSERTERMINATION; }

    pSatEventList->cbSize = ROUNDTODWORD2(sizeof(SIMEVENTLIST), pSatEventList->dwEventsSize);

    pSatCmd->cbSize += pSatEventList->cbSize;
    pSatCmd->dwDetailsSize = pSatEventList->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSetupCall(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nConfIconQualifier, nConfIconId, nSetupIconQualifier, nSetupIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMCALL*           pSatCall;
WCHAR              wszConfirmation[UCS2_LEN + 1], wszNumber[UCS2_LEN + 1], wszSetup[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SETUPCALL);

  // Parse "<details>,<confirmation text>,<called number>,<call setup text>,<conf icon qual>,<conf icon>,<call setup icon qual>,<call setup icon>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)                  ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUCS2String(szRsp, wszConfirmation, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUCS2String(szRsp, wszNumber, UCS2_LEN, szRsp)        ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUCS2String(szRsp, wszSetup, UCS2_LEN, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUInt(szRsp, FALSE, nConfIconQualifier, szRsp)        ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUInt(szRsp, FALSE, nConfIconId, szRsp)               ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUInt(szRsp, FALSE, nSetupIconQualifier, szRsp)       ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUInt(szRsp, FALSE, nSetupIconId, szRsp)              ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatCall = (SIMCALL*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatCall->dwParams = SIM_PARAM_SIMCALL_FLAGS;
    switch (nDetails) {
      case 0:
        pSatCall->dwFlags = SIMCALL_IDLE;
        break;
      case 1:
        pSatCall->dwFlags = SIMCALL_IDLE | SIMCALL_REDIAL;
        break;
      case 2:
        pSatCall->dwFlags = SIMCALL_HOLDCALLS;
        break;
      case 3:
        pSatCall->dwFlags = SIMCALL_HOLDCALLS | SIMCALL_REDIAL;
        break;
      case 4:
        pSatCall->dwFlags = SIMCALL_DISCONNECTCALLS;
        break;
      case 5:
        pSatCall->dwFlags = SIMCALL_DISCONNECTCALLS | SIMCALL_REDIAL;
        break;
      default:
        pSatCall->dwParams = 0;
        break;
    }
    if (wcslen(wszConfirmation)) {
      pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_TEXTSIZE | SIM_PARAM_SIMCALL_TEXTOFFSET;
      pSatCall->dwTextSize                 = (wcslen(wszConfirmation) + 1) * sizeof(WCHAR);
      pSatCall->dwTextOffset               = ROUNDTODWORD(sizeof(SIMCALL));
      wcscpy((WCHAR*)((BYTE*)pSatCall + pSatCall->dwTextOffset), wszConfirmation);
    }
    if (wcslen(wszNumber)) {
      pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_ADDRESSSIZE | SIM_PARAM_SIMCALL_ADDRESSOFFSET |
                                             SIM_PARAM_SIMCALL_ADDRESSTYPE | SIM_PARAM_SIMCALL_NUMPLAN;
      pSatCall->dwAddressSize              = (wcslen(wszNumber) + 1) * sizeof(WCHAR);
      pSatCall->dwAddressOffset            = ROUNDTODWORD2(sizeof(SIMCALL), pSatCall->dwTextSize);
      pSatCall->dwAddressType              = (wszNumber[0] == L'+') ? SIM_ADDRTYPE_INTERNATIONAL : SIM_ADDRTYPE_UNKNOWN;
      pSatCall->dwNumPlan                  = SIM_NUMPLAN_TELEPHONE;
      wcscpy((WCHAR*)((BYTE*)pSatCall + pSatCall->dwAddressOffset), wszNumber);
    }
    if (wcslen(wszSetup)) {
      pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_CALLSETUPTEXTSIZE | SIM_PARAM_SIMCALL_CALLSETUPTEXTOFFSET;
      pSatCall->dwCallSetupTextSize        = (wcslen(wszSetup) + 1) * sizeof(WCHAR);
      pSatCall->dwCallSetupTextOffset      = ROUNDTODWORD3(sizeof(SIMCALL), pSatCall->dwTextSize, pSatCall->dwAddressSize);
      wcscpy((WCHAR*)((BYTE*)pSatCall + pSatCall->dwCallSetupTextOffset), wszSetup);
    }
    if (nConfIconId) {
      pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_ICONID | SIM_PARAM_SIMCALL_ICONQUALIFIER;
      pSatCall->dwIconIdentifier           = nConfIconId;
      pSatCall->dwIconQualifier            = nConfIconQualifier;
    }
    if (nSetupIconId) {
      pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_CALLSETUPICONID | SIM_PARAM_SIMCALL_CALLSETUPICONQUALIFIER;
      pSatCall->dwCallSetupIconIdentifier  = nSetupIconId;
      pSatCall->dwCallSetupIconQualifier   = nSetupIconQualifier;
    }
    pSatCall->cbSize = ROUNDTODWORD4(sizeof(SIMCALL), pSatCall->dwTextSize, pSatCall->dwAddressSize, pSatCall->dwCallSetupTextSize);

    pSatCmd->cbSize += pSatCall->cbSize;
    pSatCmd->dwDetailsSize = pSatCall->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendSS(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMUSSD*           pSatSs;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SENDSS);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatSs = (SIMUSSD*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    if (wcslen(wszText)) {
      pSatSs->dwParams         |= SIM_PARAM_SIMUSSD_TEXTSIZE | SIM_PARAM_SIMUSSD_TEXTOFFSET;
      pSatSs->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatSs->dwTextOffset      = ROUNDTODWORD(sizeof(SIMUSSD));
      wcscpy((WCHAR*)((BYTE*)pSatSs + pSatSs->dwTextOffset), wszText);
    }
    if (nIconId) {
      pSatSs->dwParams         |= SIM_PARAM_SIMUSSD_ICONID | SIM_PARAM_SIMUSSD_ICONQUALIFIER;
      pSatSs->dwIconIdentifier  = nIconId;
      pSatSs->dwIconQualifier   = nIconQualifier;
    }
    pSatSs->cbSize = ROUNDTODWORD2(sizeof(SIMUSSD), pSatSs->dwTextSize);

    pSatCmd->cbSize += pSatSs->cbSize;
    pSatCmd->dwDetailsSize = pSatSs->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendUSSD(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMUSSD*           pSatUssd;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SENDUSSD);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatUssd = (SIMUSSD*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    if (wcslen(wszText)) {
      pSatUssd->dwParams         |= SIM_PARAM_SIMUSSD_TEXTSIZE | SIM_PARAM_SIMUSSD_TEXTOFFSET;
      pSatUssd->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatUssd->dwTextOffset      = ROUNDTODWORD(sizeof(SIMUSSD));
      wcscpy((WCHAR*)((BYTE*)pSatUssd + pSatUssd->dwTextOffset), wszText);
    }
    if (nIconId) {
      pSatUssd->dwParams         |= SIM_PARAM_SIMUSSD_ICONID | SIM_PARAM_SIMUSSD_ICONQUALIFIER;
      pSatUssd->dwIconIdentifier  = nIconId;
      pSatUssd->dwIconQualifier   = nIconQualifier;
    }
    pSatUssd->cbSize = ROUNDTODWORD2(sizeof(SIMUSSD), pSatUssd->dwTextSize);

    pSatCmd->cbSize += pSatUssd->cbSize;
    pSatCmd->dwDetailsSize = pSatUssd->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendSMS(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMSMS*            pSatSms;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SENDSMS);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatSms = (SIMSMS*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    if (wcslen(wszText)) {
      pSatSms->dwParams         |= SIM_PARAM_SIMSMS_TEXTSIZE | SIM_PARAM_SIMSMS_TEXTOFFSET;
      pSatSms->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatSms->dwTextOffset      = ROUNDTODWORD(sizeof(SIMSMS));
      wcscpy((WCHAR*)((BYTE*)pSatSms + pSatSms->dwTextOffset), wszText);
    }
    if (nIconId) {
      pSatSms->dwParams         |= SIM_PARAM_SIMSMS_ICONID | SIM_PARAM_SIMSMS_ICONQUALIFIER;
      pSatSms->dwIconIdentifier  = nIconId;
      pSatSms->dwIconQualifier   = nIconQualifier;
    }
    pSatSms->cbSize = ROUNDTODWORD2(sizeof(SIMSMS), pSatSms->dwTextSize);

    pSatCmd->cbSize += pSatSms->cbSize;
    pSatCmd->dwDetailsSize = pSatSms->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendDTMF(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMSENDDTMF*       pSatDtmf;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SENDDTMF);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatDtmf = (SIMSENDDTMF*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    if (wcslen(wszText)) {
      pSatDtmf->dwParams         |= SIM_PARAM_SIMSENDDTMF_TEXTSIZE | SIM_PARAM_SIMSENDDTMF_TEXTOFFSET;
      pSatDtmf->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatDtmf->dwTextOffset      = ROUNDTODWORD(sizeof(SIMSENDDTMF));
      wcscpy((WCHAR*)((BYTE*)pSatDtmf + pSatDtmf->dwTextOffset), wszText);
    }
    if (nIconId) {
      pSatDtmf->dwParams         |= SIM_PARAM_SIMSENDDTMF_ICONID | SIM_PARAM_SIMSENDDTMF_ICONQUALIFIER;
      pSatDtmf->dwIconIdentifier  = nIconId;
      pSatDtmf->dwIconQualifier   = nIconQualifier;
    }
    pSatDtmf->cbSize = ROUNDTODWORD2(sizeof(SIMSENDDTMF), pSatDtmf->dwTextSize);

    pSatCmd->cbSize += pSatDtmf->cbSize;
    pSatCmd->dwDetailsSize = pSatDtmf->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseLaunchBrowser(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT                 nDetails, nIconQualifier, nIconId, nBrowserId;
RILSIMTOOLKITCMD*    pSatCmd;
SIMLAUNCHBROWSER*    pSatLB;
WCHAR                wszText[UCS2_LEN + 1], wszURL[UCS2_LEN + 1], wszGateway[UCS2_LEN + 1];
WCHAR                wszBearerLst[UCS2_LEN + 1], wszFileRefLst[UCS2_LEN + 1]; //Not supported by module
BOOL                 fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_LAUNCHBROWSER);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>,<browserid>,<url>,<bearerlist>,<filereflist>,<gatewayid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)                ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)        ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)                 ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUInt(szRsp, FALSE, nBrowserId, szRsp)              ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUCS2String(szRsp, wszURL, UCS2_LEN, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUCS2String(szRsp, wszBearerLst, UCS2_LEN, szRsp)   ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUCS2String(szRsp, wszFileRefLst, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUCS2String(szRsp, wszGateway, UCS2_LEN, szRsp)     ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatLB = (SIMLAUNCHBROWSER*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatLB->dwParams            = SIM_PARAM_SIMLAUNCHBROWSER_FLAGS | SIM_PARAM_SIMLAUNCHBROWSER_BROWSERID;
    pSatLB->dwFlags             = nDetails;
    pSatLB->dwBrowserId         = nBrowserId;
    if (wcslen(wszURL)) {
      pSatLB->dwParams         |= SIM_PARAM_SIMLAUNCHBROWSER_URLSIZE | SIM_PARAM_SIMLAUNCHBROWSER_URLOFFSET;
      pSatLB->dwURLSize         = (wcslen(wszURL) + 1) * sizeof(WCHAR);
      pSatLB->dwURLOffset       = ROUNDTODWORD(sizeof(SIMLAUNCHBROWSER));
      wcscpy((WCHAR*)((BYTE*)pSatLB + pSatLB->dwURLOffset), wszURL);
    }
    if (wcslen(wszText)) {
      pSatLB->dwParams         |= SIM_PARAM_SIMLAUNCHBROWSER_TEXTSIZE | SIM_PARAM_SIMLAUNCHBROWSER_TEXTOFFSET;
      pSatLB->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatLB->dwTextOffset      = ROUNDTODWORD2(sizeof(SIMLAUNCHBROWSER), pSatLB->dwURLSize);
      wcscpy((WCHAR*)((BYTE*)pSatLB + pSatLB->dwTextOffset), wszText);
    }
    if (nIconId) {
      pSatLB->dwParams         |= SIM_PARAM_SIMLAUNCHBROWSER_ICONID | SIM_PARAM_SIMLAUNCHBROWSER_ICONQUALIFIER;
      pSatLB->dwIconIdentifier  = nIconId;
      pSatLB->dwIconQualifier   = nIconQualifier;
    }
    pSatLB->cbSize = ROUNDTODWORD3(sizeof(SIMLAUNCHBROWSER), pSatLB->dwURLSize, pSatLB->dwTextSize);

    pSatCmd->cbSize += pSatLB->cbSize;
    pSatCmd->dwDetailsSize = pSatLB->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParsePlayTone(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nTone, nDurationUnit, nDuration, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMTONE*           pSatTone;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_PLAYTONE);

  // Parse: "<details>,<"text">,<tone>,<durationunit>,<duration>,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nTone, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nDurationUnit, szRsp)     ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nDuration, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatTone = (SIMTONE*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatTone->dwParams    = SIM_PARAM_SIMTONE_TONE | SIM_PARAM_SIMTONE_DURATION;
    pSatTone->dwTone      = nTone;
    pSatTone->dwDuration  = 0;
    switch (nDurationUnit) {
      case 0:
        pSatTone->dwDuration = nDuration * (60 * 1000);
        break;
      case 1:
        pSatTone->dwDuration = nDuration * 1000;
        break;
      case 2:
        pSatTone->dwDuration = nDuration * 100;
        break;
      default:
        PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_COMMANDDATA);
        fRet = FALSE;
        break;
    }
    if (wcslen(wszText)) {
      pSatTone->dwParams         |= SIM_PARAM_SIMTONE_TEXTSIZE | SIM_PARAM_SIMTONE_TEXTOFFSET;
      pSatTone->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatTone->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTONE));
      wcscpy((WCHAR*)((BYTE*)pSatTone + pSatTone->dwTextOffset), wszText);
    }
    if (nIconId) {
      pSatTone->dwParams         |= SIM_PARAM_SIMTONE_ICONID | SIM_PARAM_SIMTONE_ICONQUALIFIER;
      pSatTone->dwIconIdentifier  = nIconId;
      pSatTone->dwIconQualifier   = nIconQualifier;
    }
    pSatTone->cbSize = ROUNDTODWORD2(sizeof(SIMTONE), pSatTone->dwTextSize);

    pSatCmd->cbSize += pSatTone->cbSize;
    pSatCmd->dwDetailsSize = pSatTone->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseDisplayText(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nImmediateResp, nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMTEXT*           pSatText;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_DISPLAYTEXT);

  // Parse: "<details>,<"text">,<immediateresponse>,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nImmediateResp, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatText->dwParams            = SIM_PARAM_SIMTEXT_FLAGS;
    if (nImmediateResp)           { pSatText->dwFlags |= SIMTEXT_IMMEDIATERESPONSE; }
    if (nDetails & 0x01)          { pSatText->dwFlags |= SIMTEXT_HIGHPRIORITY; }
    if (!(nDetails & 0x80))       { pSatText->dwFlags |= SIMTEXT_DELAYCLEAR; }
    if (wcslen(wszText)) {
      pSatText->dwParams         |= SIM_PARAM_SIMTEXT_TEXTSIZE | SIM_PARAM_SIMTEXT_TEXTOFFSET;
      pSatText->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatText->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTEXT));
      wcscpy((WCHAR*)((BYTE*)pSatText + pSatText->dwTextOffset), wszText);
    }
    if (nIconId) {
      pSatText->dwParams         |= SIM_PARAM_SIMTEXT_ICONID | SIM_PARAM_SIMTEXT_ICONQUALIFIER;
      pSatText->dwIconIdentifier  = nIconId;
      pSatText->dwIconQualifier   = nIconQualifier;
    }
    pSatText->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);

    pSatCmd->cbSize += pSatText->cbSize;
    pSatCmd->dwDetailsSize = pSatText->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseGetInkey(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMTEXT*           pSatText;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_GETINKEY);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatText->dwParams = SIM_PARAM_SIMTEXT_FLAGS;
    if (nDetails & 0x04) {
      pSatText->dwFlags |= SIMTEXT_YESNO;
    } else {
      if (!(nDetails & 0x01)) {
        pSatText->dwFlags |= SIMTEXT_KEYPADDIGITS;
      }
      if (!(nDetails & 0x02)) {
        pSatText->dwFlags |= SIMTEXT_GSMDEFAULTALPHABET;
      }
    }
    if (nDetails & 0x80) {
      pSatText->dwFlags |= SIMTEXT_HELPINFO;
    }
    if (wcslen(wszText)) {
      pSatText->dwParams         |= SIM_PARAM_SIMTEXT_TEXTSIZE | SIM_PARAM_SIMTEXT_TEXTOFFSET;
      pSatText->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatText->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTEXT));
      wcscpy((WCHAR*)((BYTE*)pSatText + pSatText->dwTextOffset), wszText);
    }
    if (nIconId) {
      pSatText->dwParams         |= SIM_PARAM_SIMTEXT_ICONID | SIM_PARAM_SIMTEXT_ICONQUALIFIER;
      pSatText->dwIconIdentifier  = nIconId;
      pSatText->dwIconQualifier   = nIconQualifier;
    }
    pSatText->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);

    pSatCmd->cbSize += pSatText->cbSize;
    pSatCmd->dwDetailsSize = pSatText->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseGetInput(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
UINT               nResponseMin, nResponseMax;
RILSIMTOOLKITCMD*  pSatCmd;
SIMTEXT*           pSatText;
WCHAR              wszText[UCS2_LEN + 1], wszDefaultText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_GETINPUT);

  // Parse: "<details>,<"text">,<responsemin>,<responsemax>,<"defaulttext">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)                 ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nResponseMin, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nResponseMax, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUCS2String(szRsp, wszDefaultText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)           ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)                  ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatText->dwParams               = SIM_PARAM_SIMTEXT_FLAGS;
    if (!(nDetails & 0x01))          { pSatText->dwFlags |= SIMTEXT_KEYPADDIGITS; }
    if (!(nDetails & 0x02))          { pSatText->dwFlags |= SIMTEXT_GSMDEFAULTALPHABET; }
    if (nDetails & 0x04)             { pSatText->dwFlags |= SIMTEXT_NOECHO; }
    if (nDetails & 0x08)             { pSatText->dwFlags |= SIMTEXT_PACKEDRESPONSE; }
    if (nDetails & 0x80)             { pSatText->dwFlags |= SIMTEXT_HELPINFO; }
    pSatText->dwMinResponse          = nResponseMin;
    pSatText->dwMaxResponse          = nResponseMax;
    if (wcslen(wszText)) {
      pSatText->dwParams            |= SIM_PARAM_SIMTEXT_TEXTSIZE | SIM_PARAM_SIMTEXT_TEXTOFFSET;
      pSatText->dwTextSize           = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatText->dwTextOffset         = ROUNDTODWORD(sizeof(SIMTEXT));
      wcscpy((WCHAR*)((BYTE*)pSatText + pSatText->dwTextOffset), wszText);
    }
    if (wcslen(wszText)) {
      pSatText->dwParams            |= SIM_PARAM_SIMTEXT_DEFAULTTEXTSIZE | SIM_PARAM_SIMTEXT_DEFAULTTEXTOFFSET;
      pSatText->dwDefaultTextSize    = (wcslen(wszDefaultText) + 1) * sizeof(WCHAR);
      pSatText->dwDefaultTextOffset  = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);
      wcscpy((WCHAR*)((BYTE*)pSatText + pSatText->dwDefaultTextOffset), wszDefaultText);
    }
    if (nIconId) {
      pSatText->dwParams            |= SIM_PARAM_SIMTEXT_ICONID | SIM_PARAM_SIMTEXT_ICONQUALIFIER;
      pSatText->dwIconIdentifier     = nIconId;
      pSatText->dwIconQualifier      = nIconQualifier;
    }
    pSatText->cbSize = ROUNDTODWORD3(sizeof(SIMTEXT), pSatText->dwTextSize, pSatText->dwDefaultTextSize);

    pSatCmd->cbSize += pSatText->cbSize;
    pSatCmd->dwDetailsSize = pSatText->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSelectItem(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               i, nCmd, nNumItems, nDetails, nItem, nDefaultItem;
UINT               nItemIconsPresent, nItemIconsQualifier, nTitleIconQualifier, nTitleIconId;
UINT               nNextActionId, nIconId;
DWORD              dwLen;
RILSIMTOOLKITCMD*  pSatCmd;
SIMMENU*           pSatMenu;
SIMMENUITEM*       pSatItem;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SELECTITEM);

  // Parse Title: "<details>,<numitems>,<"titletext">,<>defaultitem,<itemiconspresent>,<itemiconqualifier>,<titleiconqualifier>,<titleiconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nNumItems, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)     ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nDefaultItem, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsPresent, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconId, szRsp)         ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    // An item list without items is invalid
    if (!nNumItems) {
      PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_COMMANDDATA);
      fRet = FALSE;
    } else {
      pSatMenu = (SIMMENU*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

      pSatMenu->dwParams            = SIM_PARAM_SIMMENU_FLAGS | SIM_PARAM_SIMMENU_MENUITEMCOUNT |
                                      SIM_PARAM_SIMMENU_MENUITEMOFFSET | SIM_PARAM_SIMMENU_MENUITEMSIZE;
      if (nDetails & 0x80)          { pSatMenu->dwFlags = SIMMENU_HELPINFO; }
      if (wcslen(wszText)) {
        pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_TEXTSIZE | SIM_PARAM_SIMMENU_TEXTOFFSET;
        pSatMenu->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
        pSatMenu->dwTextOffset      = ROUNDTODWORD(sizeof(SIMMENU));
        wcscpy((WCHAR*)((BYTE*)pSatMenu + pSatMenu->dwTextOffset), wszText);
      }
      if (nDefaultItem) {
        pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_DEFAULTITEM;
        pSatMenu->dwDefaultItem     = nDefaultItem;
      }
      if (nTitleIconId) {
        pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_ICONID | SIM_PARAM_SIMMENU_ICONQUALIFIER;
        pSatMenu->dwIconIdentifier  = nTitleIconId;
        pSatMenu->dwIconQualifier   = nTitleIconQualifier;
      }
      pSatMenu->dwMenuItemCount     = nNumItems;
      pSatMenu->dwMenuItemOffset    = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);

      pSatMenu->cbSize = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);

      pSatItem = (SIMMENUITEM*)((BYTE*)pSatMenu + pSatMenu->dwMenuItemOffset);

      for (i = 0; i < nNumItems; i++) {
        // Parse Item: "^SSTGI: <cmdtype>,<itemid>,"itemtext",<nextactionid>,<iconid>"
        if (!MatchStringBeginning(szRsp, "^SSTGI: ", szRsp)    ||
            !ParseUInt(szRsp, FALSE, nCmd, szRsp)              ||
            !ParseRspParamSeparator(szRsp, szRsp)              ||
            !ParseUInt(szRsp, FALSE, nItem, szRsp)             ||
            !ParseRspParamSeparator(szRsp, szRsp)              ||
            !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
            !ParseRspParamSeparator(szRsp, szRsp)              ||
            !ParseUInt(szRsp, FALSE, nNextActionId, szRsp)     ||
            !ParseRspParamSeparator(szRsp, szRsp)              ||
            !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
            !ParseRspPostfix(szRsp, szRsp)) {
          PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
          fRet = FALSE;
          break;
        }

        dwLen = wcslen(wszText);
        if (dwLen) {
          dwLen = (dwLen + 1) * sizeof(WCHAR);
        }
        if (((BYTE*)pSatItem + ROUNDTODWORD2(sizeof(SIMMENUITEM), dwLen)) >= &(m_bCmdBuffer[SIMTK_MAX_LENGTH])) {
          // Our temporary buffer on the stack is too small
          PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_COMMANDDATA);
          fRet = FALSE;
          break;
        }

        pSatItem->dwParams            = SIM_PARAM_SIMMENUITEM_FLAGS | SIM_PARAM_SIMMENUITEM_IDENTIFIER;
        if (nDetails & 0x80)          { pSatItem->dwFlags = SIMMENU_HELPINFO; }
        pSatItem->dwIdentifier        = nItem;
        if (dwLen) {
          pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_TEXTSIZE | SIM_PARAM_SIMMENUITEM_TEXTOFFSET;
          pSatItem->dwTextSize        = dwLen;
          pSatItem->dwTextOffset      = ROUNDTODWORD(sizeof(SIMMENUITEM));
          wcscpy((WCHAR*)((BYTE*)pSatItem + pSatItem->dwTextOffset), wszText);
        }
        if (nNextActionId) {
          pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_NEXTACTION;
          pSatItem->dwNextAction      = nNextActionId;
        }
        if (nIconId && nItemIconsPresent) {
          pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_ICONID | SIM_PARAM_SIMMENUITEM_ICONQUALIFIER;
          pSatItem->dwIconIdentifier  = nIconId;
          pSatItem->dwIconQualifier   = nItemIconsQualifier;
        }
        pSatItem->cbSize = ROUNDTODWORD2(sizeof(SIMMENUITEM), pSatItem->dwTextSize);

        pSatMenu->dwMenuItemSize += pSatItem->cbSize;

        pSatItem = (SIMMENUITEM*)((BYTE*)pSatItem + pSatItem->cbSize);
      }
      if (fRet) {
        pSatMenu->cbSize += pSatMenu->dwMenuItemSize;
        pSatCmd->cbSize += pSatMenu->cbSize;
        pSatCmd->dwDetailsSize = pSatMenu->cbSize;
      }
    }
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSetupMenu(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               i, nCmd, nNumItems, nDetails, nItem;
UINT               nItemIconsPresent, nItemIconsQualifier, nTitleIconQualifier, nTitleIconId;
UINT               nNextActionId, nIconId;
DWORD              dwLen;
RILSIMTOOLKITCMD*  pSatCmd;
SIMMENU*           pSatMenu;
SIMMENUITEM*       pSatItem;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SETUPMENU);

  // Parse Title: "<details>,<numitems>,<"titletext">,<itemiconspresent>,<itemiconqualifier>,<titleiconqualifier>,<titleiconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nNumItems, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)     ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsPresent, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconId, szRsp)         ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatMenu = (SIMMENU*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatMenu->dwParams            = SIM_PARAM_SIMMENU_FLAGS | SIM_PARAM_SIMMENU_MENUITEMCOUNT |
                                    SIM_PARAM_SIMMENU_MENUITEMOFFSET | SIM_PARAM_SIMMENU_MENUITEMSIZE;
    if (nDetails & 0x80)          { pSatMenu->dwFlags = SIMMENU_HELPINFO; }
    if (wcslen(wszText)) {
      pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_TEXTSIZE | SIM_PARAM_SIMMENU_TEXTOFFSET;
      pSatMenu->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatMenu->dwTextOffset      = ROUNDTODWORD(sizeof(SIMMENU));
      wcscpy((WCHAR*)((BYTE*)pSatMenu + pSatMenu->dwTextOffset), wszText);
    }
    if (nTitleIconId) {
      pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_ICONID | SIM_PARAM_SIMMENU_ICONQUALIFIER;
      pSatMenu->dwIconIdentifier  = nTitleIconId;
      pSatMenu->dwIconQualifier   = nTitleIconQualifier;
    }
    pSatMenu->dwMenuItemCount     = nNumItems;
    pSatMenu->dwMenuItemOffset    = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);

    pSatMenu->cbSize = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);

    pSatItem = (SIMMENUITEM*)((BYTE*)pSatMenu + pSatMenu->dwMenuItemOffset);

    for (i = 0; i < nNumItems; i++) {
      // Parse Item: "^SSTGI: <cmdtype>,<itemid>,"itemtext",<nextactionid>,<iconid>"
      if (!MatchStringBeginning(szRsp, "^SSTGI: ", szRsp)    ||
          !ParseUInt(szRsp, FALSE, nCmd, szRsp)              ||
          !ParseRspParamSeparator(szRsp, szRsp)              ||
          !ParseUInt(szRsp, FALSE, nItem, szRsp)             ||
          !ParseRspParamSeparator(szRsp, szRsp)              ||
          !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
          !ParseRspParamSeparator(szRsp, szRsp)              ||
          !ParseUInt(szRsp, FALSE, nNextActionId, szRsp)     ||
          !ParseRspParamSeparator(szRsp, szRsp)              ||
          !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
          !ParseRspPostfix(szRsp, szRsp)) {
        PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
        fRet = FALSE;
        break;
      }

      dwLen = wcslen(wszText);
      if (dwLen) {
        dwLen = (dwLen + 1) * sizeof(WCHAR);
      }
      if (((BYTE*)pSatItem + ROUNDTODWORD2(sizeof(SIMMENUITEM), dwLen)) >= &(m_bCmdBuffer[SIMTK_MAX_LENGTH])) {
        // Our temporary buffer on the stack is too small
        PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_COMMANDDATA);
        fRet = FALSE;
        break;
      }

      pSatItem->dwParams            = SIM_PARAM_SIMMENUITEM_FLAGS | SIM_PARAM_SIMMENUITEM_IDENTIFIER;
      if (nDetails & 0x80)          { pSatItem->dwFlags = SIMMENU_HELPINFO; }
      pSatItem->dwIdentifier        = nItem;
      if (dwLen) {
        pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_TEXTSIZE | SIM_PARAM_SIMMENUITEM_TEXTOFFSET;
        pSatItem->dwTextSize        = dwLen;
        pSatItem->dwTextOffset      = ROUNDTODWORD(sizeof(SIMMENUITEM));
        wcscpy((WCHAR*)((BYTE*)pSatItem + pSatItem->dwTextOffset), wszText);
      }
      if (nNextActionId) {
        pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_NEXTACTION;
        pSatItem->dwNextAction      = nNextActionId;
      }
      if (nIconId && nItemIconsPresent) {
        pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_ICONID | SIM_PARAM_SIMMENUITEM_ICONQUALIFIER;
        pSatItem->dwIconIdentifier  = nIconId;
        pSatItem->dwIconQualifier   = nItemIconsQualifier;
      }
      pSatItem->cbSize = ROUNDTODWORD2(sizeof(SIMMENUITEM), pSatItem->dwTextSize);

      pSatMenu->dwMenuItemSize += pSatItem->cbSize;

      pSatItem = (SIMMENUITEM*)((BYTE*)pSatItem + pSatItem->cbSize);
    }
    if (fRet) {
      pSatMenu->cbSize += pSatMenu->dwMenuItemSize;
      pSatCmd->cbSize += pSatMenu->cbSize;
      pSatCmd->dwDetailsSize = pSatMenu->cbSize;
    }
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseIdleText(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMTEXT*           pSatText;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SETUPIDLEMODETEXT);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    if (wcslen(wszText)) {
      pSatText->dwParams          = SIM_PARAM_SIMTEXT_TEXTSIZE | SIM_PARAM_SIMTEXT_TEXTOFFSET;
      pSatText->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatText->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTEXT));
      wcscpy((WCHAR*)((BYTE*)pSatText + pSatText->dwTextOffset), wszText);
    }
    if (nIconId) {
      pSatText->dwParams         |= SIM_PARAM_SIMTEXT_ICONID | SIM_PARAM_SIMTEXT_ICONQUALIFIER;
      pSatText->dwIconIdentifier  = nIconId;
      pSatText->dwIconQualifier   = nIconQualifier;
    }
    pSatText->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);

    pSatCmd->cbSize += pSatText->cbSize;
    pSatCmd->dwDetailsSize = pSatText->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function called to parse the response to a SIM-Toolkit command.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::ParseGetCommand(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) {
UINT                  nCmd;
CSimToolkitHandling*  pInstance = (CSimToolkitHandling*)pParam;
HRESULT               hr = S_OK;

  pBlob = 0;
  cbBlob = 0;

  if (!pInstance) {
    return E_FAIL;
  }

  pInstance->m_fNoResponse = FALSE;

  // Parse "<prefix>^SSTGI: <cmdtype>"
  if (!ParseRspPrefix(szRsp, szRsp)                    ||
      !MatchStringBeginning(szRsp, "^SSTGI: ", szRsp)  ||
      !ParseUInt(szRsp, FALSE, nCmd, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)) {
    return E_FAIL;
  }

  RILRetailTrace((TEXT("RilDrv: SimToolkit: ParseGetCommand: %d\r\n"), nCmd));

  EnterCriticalSection(&(pInstance->m_csLockBuffer));

  switch (nCmd) {
    case SIMTK_CMD_REFRESH:
      if (!pInstance->ParseRefresh(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - REFRESH command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_EVENTLIST:
      if (!pInstance->ParseSetupEventList(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - REFRESH command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_CALL:
      if (!pInstance->ParseSetupCall(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SETUP CALL command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SEND_SS:
      if (!pInstance->ParseSendSS(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SEND SS command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SEND_USSD:
      if (!pInstance->ParseSendUSSD(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SEND USSD command format corrupt\r\n")));
        hr = E_FAIL;
      } else {
        // Because the MMI isn't calling back the RIL with the SAT response we have to generate it on our own
        RILSIMTOOLKITRSP Rsp;
        memset(&Rsp, 0, sizeof(RILSIMTOOLKITRSP));
        Rsp.cbSize = sizeof(RILSIMTOOLKITRSP);
        Rsp.dwParams = RIL_PARAM_SIMTKIT_RSP_TYPE | RIL_PARAM_SIMTKIT_RSP_RESPONSE;
        Rsp.dwType = SIM_NOTIFY_SENDUSSD;
        Rsp.dwResponse = SIM_RESPONSE_OK;
        if (FAILED(pInstance->SendCmdResponse(NULL, &Rsp, NULL, 0))) {
          hr = E_FAIL;
        }
      }
      break;

    case SIMTK_CMD_SEND_SMS:
      if (!pInstance->ParseSendSMS(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SEND SMS command format corrupt\r\n")));
        hr = E_FAIL;
      } else {
        // Because the MMI isn't calling back the RIL with the SAT response we have to generate it on our own
        RILSIMTOOLKITRSP Rsp;
        memset(&Rsp, 0, sizeof(RILSIMTOOLKITRSP));
        Rsp.cbSize = sizeof(RILSIMTOOLKITRSP);
        Rsp.dwParams = RIL_PARAM_SIMTKIT_RSP_TYPE | RIL_PARAM_SIMTKIT_RSP_RESPONSE;
        Rsp.dwType = SIM_NOTIFY_SENDSMS;
        Rsp.dwResponse = SIM_RESPONSE_OK;
        if (FAILED(pInstance->SendCmdResponse(NULL, &Rsp, NULL, 0))) {
          hr = E_FAIL;
        }
      }
      break;

    case SIMTK_CMD_SEND_DTMF:
      if (!pInstance->ParseSendDTMF(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SEND DTMF command format corrupt\r\n")));
        hr = E_FAIL;
      } else {
        // To get the MMI handle the DTMF command correctly we have to generate our own success response
        RILSIMTOOLKITRSP  Rsp;
        memset(&Rsp, 0, sizeof(RILSIMTOOLKITRSP));
        Rsp.dwParams = RIL_PARAM_SIMTKIT_RSP_TYPE | RIL_PARAM_SIMTKIT_RSP_RESPONSE;
        Rsp.cbSize = sizeof(RILSIMTOOLKITRSP);
        Rsp.dwType = nCmd;
        Rsp.dwResponse = SIM_RESPONSE_OK;
        hr = pInstance->SendCmdResponse(NULL, &Rsp, NULL, 0);
      }
      break;

    case SIMTK_CMD_LAUNCH_BROWSER:
      if (!pInstance->ParseLaunchBrowser(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - LAUNCH BROWSER command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_PLAY_TONE:
      if (!pInstance->ParsePlayTone(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - PLAY TONE command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_DISPLAY_TEXT:
      if (!pInstance->ParseDisplayText(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit - DISPLAY TEXT command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_GET_INKEY:
      if (!pInstance->ParseGetInkey(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit - GET INKEY command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_GET_INPUT:
      if (!pInstance->ParseGetInput(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - GET INPUT command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SELECT_ITEM:
      if (!pInstance->ParseSelectItem(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SELECT ITEM command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_MENU:
      if (!pInstance->ParseSetupMenu(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SETUP MENU command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_IDLE_TEXT:
      if (!pInstance->ParseIdleText(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SETUP IDLETEXT command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_GET_ICON_DATA:
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Unsupported SAT command: %i\r\n"), nCmd));
      hr = E_FAIL;
      break;

    default:
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Unknown SAT command (%i)\r\n"), nCmd));
      hr = E_FAIL;
      break;
  }

  LeaveCriticalSection(&(pInstance->m_csLockBuffer));

  // Check if anything went wrong
  if (FAILED(hr)) {
    // Try to bring the module back into a proper state
    char szCmd[32];
    sprintf(szCmd, "AT^SSTR=%d,32\r", nCmd);
    if (!QueueInternalCmd(COMMAND_PORT, pInstance->m_pRilDevice, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, 0, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY)) {
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Failed to queue cancel cmd (%i)\r\n"), nCmd));
    }
    if (!QueueInternalCmd(COMMAND_PORT, pInstance->m_pRilDevice, "AT^SSTR=254\r", CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, 0, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY)) {
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Failed to queue quit cmd\r\n")));
    }
  }

  return S_OK;
}

//////////////////////////////////////////////////////////////////////////////
//
// Send the response to a Sim-Toolkit event.
//
// Params:
//  pHandle    : Pointer to CRilInstanceHandle to be used for the operation.
//  lpbResponse: The response to send to the module.
//  dwSize     : The soze of the response.
//
// Return:
//  S_OK on successs, an error code otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::SendCmdResponse(CRilInstanceHandle* pHandle, const RILSIMTOOLKITRSP* pRsp, LPBYTE pDetails, const DWORD dwDetailsSize) {
SIMTKITRSPITEM*  pItemDetails;
SIMTKITRSPTEXT*  pTextDetails;
LPWSTR           wszText;
BOOL             fEmpty;
DWORD            dwId;
DWORD            dwResponse;
UINT             i;
char             szCmd[MAX_ATCMD_LEN];
char             szUCS2[5];
HRESULT          hr = S_OK;

  // Check some input conditions
  if (!(pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_TYPE) || !(pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_RESPONSE)) {
    return E_INVALIDARG;
  }

  // Check if we have to suppress the response
  if (m_fNoResponse) {
    return S_OK;
  }

  // Check the additional info field
  dwResponse = pRsp->dwResponse;
  if ((pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_ADDITIONALINFO) && (dwResponse == SIM_RESPONSE_ERR_MOBILEUNABLE)) {
    if (pRsp->dwAdditionalInfo == SIM_RESPONSE_ERR_MOBILEUNABLE_SCREENBUSY) {
      dwResponse = SIMTK_RSP_SCREEN_BUSY;
    }
  }

  // Check the command and build up the appropriate response.
  switch (pRsp->dwType) {
    case SIM_NOTIFY_SETUPCALL:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: SETUP CALL command response\r\n")));
      switch (dwResponse) {
        case SIM_RESPONSE_OK:
          // Currently the MMI must handle the call -> simply tell module to terminate SIM session
          dwResponse = SIM_RESPONSE_OK_ENDSESSION;
          break;
        case SIM_RESPONSE_OK_NORESPONSE:
          // For unknown reason the "no response" response is not accepted by module SAT interface
          // -> Tell module that the call has been rejected in this case
          dwResponse = SIM_RESPONSE_ERR_CALLSETUPREJECTED;
          break;
      }
      // Compose the call setup response
      sprintf(szCmd, "AT^SSTR=16,%d\r", dwResponse);
      break;

    case SIM_NOTIFY_SELECTITEM:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: SELECT ITEM command response\r\n")));
      // Get the item id if available.
      dwId = 0;
      if (pDetails && (dwDetailsSize == sizeof(SIMTKITRSPITEM))) {
        pItemDetails = (SIMTKITRSPITEM*)pDetails;
        if (pItemDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_ITEM_ID) {
          dwId = pItemDetails->dwId;
        }
      }
      // Check some input conditions
      if ((dwResponse == SIM_RESPONSE_OK) && !dwId) {
        dwResponse = SIM_RESPONSE_ERR_MOBILEUNABLE;
        hr = E_INVALIDARG;
      }
      // Compose the select item response
      sprintf(szCmd, "AT^SSTR=36,%d,%d\r", dwResponse, dwId);
      break;

    case SIM_NOTIFY_GETINKEY:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: GET INKEY command response\r\n")));
      fEmpty = TRUE;
      // Check that the details has the proper size.
      if (!pDetails || (dwDetailsSize < sizeof(SIMTKITRSPTEXT))) {
        // Send error message
        if (dwResponse == SIM_RESPONSE_OK) {
          dwResponse = SIM_RESPONSE_ERR_MOBILEUNABLE;
        }
        hr = E_INVALIDARG;
      } else {
        pTextDetails = (SIMTKITRSPTEXT*)pDetails;
        // Compose the Input response
        if (pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_YESNO) {
          // Yes/no answer
          fEmpty = FALSE;
          if (pTextDetails->dwYesNo) {
            // Send "Y"
            sprintf(szCmd, "AT^SSTR=34,%d,,\"0059\"\r", dwResponse);
          } else {
            // Send "N"
            sprintf(szCmd, "AT^SSTR=34,%d,,\"004E\"\r", dwResponse);
          }
        } else {
          // Check that the details has the proper size.
          if ((pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_TEXTOFFSET) &&
              (pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_TEXTSIZE) &&
              (pTextDetails->dwTextSize >= sizeof(WCHAR))) {
            if (dwDetailsSize < (sizeof(SIMTKITRSPTEXT) + sizeof(WCHAR))) {
              // Send error message
              if (dwResponse == SIM_RESPONSE_OK) {
                dwResponse = SIM_RESPONSE_ERR_MOBILEUNABLE;
              }
              hr = E_INVALIDARG;
            } else {
              // Normal answer -> send the key
              wszText = (LPWSTR)((LPBYTE)pTextDetails + pTextDetails->dwTextOffset);
              if (wszText[0]) {
                fEmpty = FALSE;
                sprintf(szCmd, "AT^SSTR=34,%d,,\"%0.4X\"\r", dwResponse, wszText[0]);
              }
            }
          }
        }
      }
      if (fEmpty) {
        // Send an empty string
        sprintf(szCmd, "AT^SSTR=34,%d,,\"\\1b\"\r", dwResponse);
      }
      break;

    case SIM_NOTIFY_GETINPUT:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: GET INPUT command response\r\n")));
      fEmpty = TRUE;
      // Check that the details is the proper size.
      if (!pDetails || (dwDetailsSize < sizeof(SIMTKITRSPTEXT))) {
        // Send error message
        if (dwResponse == SIM_RESPONSE_OK) {
          dwResponse = SIM_RESPONSE_ERR_MOBILEUNABLE;
        }
        hr = E_INVALIDARG;
      } else {
        pTextDetails = (SIMTKITRSPTEXT*)pDetails;
        // Set the text if necessary.
        if ((pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_TEXTOFFSET) &&
            (pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_TEXTSIZE) &&
            (pTextDetails->dwTextSize > 0)) {
          wszText = (LPWSTR)((LPBYTE)pTextDetails + pTextDetails->dwTextOffset);
          // Compose the Input response
          if (wcslen(wszText)) {
            fEmpty = FALSE;
            sprintf(szCmd, "AT^SSTR=35,%d,,\"", dwResponse);
            for (i = 0; i < min((pTextDetails->dwTextSize / sizeof(WCHAR)), wcslen(wszText)); i++) {
              sprintf(szUCS2, "%0.4X", wszText[i]);
              strncat(szCmd, szUCS2, max(0, MAX_ATCMD_LEN - strlen(szCmd) -1));
            }
            strncat(szCmd, "\"\r", max(0, MAX_ATCMD_LEN - strlen(szCmd) -1));
          }
        }
      }
      if (fEmpty) {
        // Send an empty string
        sprintf(szCmd, "AT^SSTR=35,%d,,\"\\1b\"\r", dwResponse);
      }
      break;

    case SIM_NOTIFY_REFRESH:
    case SIM_NOTIFY_EVENTLIST:
    case SIM_NOTIFY_SENDSS:
    case SIM_NOTIFY_SENDUSSD:
    case SIM_NOTIFY_SENDSMS:
    case SIM_NOTIFY_SENDDTMF:
    case SIM_NOTIFY_LAUNCHBROWSER:
    case SIM_NOTIFY_PLAYTONE:
    case SIM_NOTIFY_DISPLAYTEXT:
    case SIM_NOTIFY_SETUPMENU:
    case SIM_NOTIFY_SETUPIDLEMODETEXT:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: Default command response (%i)\r\n"),  pRsp->dwType));
      sprintf(szCmd, "AT^SSTR=%d,%d\r", pRsp->dwType, dwResponse);
      break;

    case SIM_NOTIFY_SETUPMENU_REPLY:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: SETUP MENU command event\r\n")));
      // Get the item id if available.
      dwId = 0;
      if (pDetails && (dwDetailsSize == sizeof(SIMTKITRSPITEM))) {
        pItemDetails = (SIMTKITRSPITEM*)pDetails;
        if (pItemDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_ITEM_ID) {
          dwId = pItemDetails->dwId;
        }
      }
      // Check some input conditions
      if ((dwResponse != SIM_RESPONSE_OK) && (dwResponse != SIM_RESPONSE_OK_HELP)) {
        return E_INVALIDARG;
      }
      if ((dwResponse == SIM_RESPONSE_OK) && !dwId) {
        return E_INVALIDARG;
      }
      // Compose the select item response
      sprintf(szCmd, "AT^SSTR=211,%d,%d\r", dwResponse, dwId);
      break;

    case SIM_NOTIFY_ENDSESSION:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: END SESSION command event\r\n")));
      sprintf(szCmd, "AT^SSTR=254\r");
      break;

    case SIM_NOTIFY_CALLSETUP:
    case SIM_NOTIFY_LANGUAGENOTIFICATION:
    case SIM_NOTIFY_EVENTDOWNLOAD:
    default:
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Unknown command response (%i)\r\n"), pRsp->dwType));
      return E_NOTIMPL;
  }

  if (pHandle) {
    if (!QueueCmdWithRetry(COMMAND_PORT, pHandle, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, NULL, NULL, hr, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY, ParseRspError, this)) {
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - unable to put CCommand into the queue\r\n")));
      return E_FAIL;
    }
  } else {
    if (!QueueInternalCmd(COMMAND_PORT, m_pRilDevice, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, 0, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY, NULL, ParseRspError, this)) {
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - unable to put CCommand into the queue\r\n")));
      return E_FAIL;
    }
  }

  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Send a Sim-Toolkit event to the module.
//
// Params:
//  pHandle      : Pointer to CRilInstanceHandle to be used for the operation.
//  dwEvent      : The type of the event
//  pDetails     : The details of the event
//  dwDetailsSize: The size of the event details
//
// Return:
//  S_OK on successs, an error code otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::SendEventDownload(CRilInstanceHandle* pHandle, const DWORD dwEvent, LPBYTE pDetails, const DWORD dwDetailsSize) {
char          szCmd[MAX_ATCMD_LEN];
SIMLANGUAGE*  pLanguageDetails;
HRESULT       hr = S_OK;

  RILRetailTrace((TEXT("RilDrv: SimToolkit-Event: %d\r\n"), dwEvent));

  // Check the command and build up the appropriate response.
  switch (dwEvent) {
    case SIMTKIT_EVENT_USERACTIVITY:
      sprintf(szCmd, "AT^SSTR=232\r");
      break;

    case SIMTKIT_EVENT_IDLESCREEN:
      sprintf(szCmd, "AT^SSTR=233\r");
      break;

    case SIMTKIT_EVENT_LANGUAGESELECTION:
      if (!pDetails || (dwDetailsSize == sizeof(SIMLANGUAGE))) {
        return E_INVALIDARG;
      }
      pLanguageDetails = (SIMLANGUAGE*)pDetails;
      if (!(pLanguageDetails->dwParams & SIM_PARAM_SIMLANGUAGE_LANGUAGE)) {
        return E_INVALIDARG;
      }
      sprintf(szCmd, "AT^SSTR=235,,,\"%c%c\"\r", (char)(pLanguageDetails->lpszLanguage[0]), (char)(pLanguageDetails->lpszLanguage[1]));
      break;

    case SIMTKIT_EVENT_BROWSERTERMINATION:
      sprintf(szCmd, "AT^SSTR=236,,%d\r", 0);
      break;

    default:
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - unknown event (0x%0.2X)\r\n"), dwEvent));
      return E_NOTIMPL;
  }

  if (!QueueCmdWithRetry(COMMAND_PORT, pHandle, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, NULL, NULL, hr, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY)) {
    RILRetailTrace((TEXT("RilDrv: SimToolkit Error - unable to put CCommand into the queue\r\n")));
    return E_FAIL;
  }

  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function called to fill a structure telling our Sim-Toolkit
// capabilities.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::ParseGetDevCapsNotifications(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) {
RILSIMTOOLKITNOTIFYCAPS*  prstnc = NULL;
RILSIMTOOLKITEVENTCAPS*   prstec = NULL;

  pBlob = NULL;
  cbBlob = 0;

  prstnc = (RILSIMTOOLKITNOTIFYCAPS *)AllocBlob(sizeof(RILSIMTOOLKITNOTIFYCAPS));
  if (!prstnc) {
      return E_OUTOFMEMORY;
  }

  memset(prstnc, 0x00, sizeof(RILSIMTOOLKITNOTIFYCAPS));

  prstnc->cbSize                 = sizeof(RILSIMTOOLKITNOTIFYCAPS);
  prstnc->dwParams               = RIL_PARAM_SIMTKN_ALL;

  prstnc->dwSetUpCall            = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwRefresh              = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;
  prstnc->dwSendSS               = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;
  prstnc->dwSendUSSD             = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;
  prstnc->dwSendSMS              = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;
  prstnc->dwSendDTMF             = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;
  prstnc->dwPlayTone             = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwDisplayText          = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwGetInkey             = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwGetInput             = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSelectItem           = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSetupMenu            = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSetupIdleModeText    = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSetupEventList       = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwLaunchBrowser        = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwLocalInfo            = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwMoreTime             = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwPollInterval         = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwPollingOff           = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwOpenChannel          = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwCloseChannel         = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwReceiveData          = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwSendData             = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwTimerManagement      = RIL_SIMTKN_NOSUPPORT;

  prstnc->dwNotifyFlags          = RIL_CAPS_NOTIFY_SIMTOOLKITCMD        |
                                   // RIL_CAPS_NOTIFY_SIMTOOLKITCALLSETUP  |
                                   RIL_CAPS_NOTIFY_SIMTOOLKITEVENT;

  prstec = &(prstnc->rstecEvents);
  prstec->cbSize                 = sizeof(RILSIMTOOLKITEVENTCAPS);
  prstec->dwParams               = RIL_PARAM_SIMTKE_ALL;

  prstec->dwUserActivity         = RIL_SIMTKN_MEIMPLEMENTS;
  prstec->dwIdleScreen           = RIL_SIMTKN_MEIMPLEMENTS;
  prstec->dwLanguageSelection    = RIL_SIMTKN_MEIMPLEMENTS;
  prstec->dwBrowserTermination   = RIL_SIMTKN_MEIMPLEMENTS;
  prstec->dwMTCall               = RIL_SIMTKN_NOSUPPORT;
  prstec->dwCallConnected        = RIL_SIMTKN_NOSUPPORT;
  prstec->dwCallDisconnected     = RIL_SIMTKN_NOSUPPORT;
  prstec->dwLocationStatus       = RIL_SIMTKN_NOSUPPORT;
  prstec->dwDataAvailable        = RIL_SIMTKN_NOSUPPORT;
  prstec->dwChannelStatus        = RIL_SIMTKN_NOSUPPORT;
  prstec->dwDisplayChange        = RIL_SIMTKN_NOSUPPORT;

  pBlob = (void*)prstnc;
  cbBlob = sizeof(RILSIMTOOLKITNOTIFYCAPS);

  return S_OK;
}

//////////////////////////////////////////////////////////////////////////////
//
// Prepare and initialize the Sim-Toolkit command structure.
//
// Params:
//  pBuffer: The buffer to be used
//  pRilCmd: Pointer to the Simtoolkit command structure (out)
//  dwType : Type of the Sim-Toolkt command
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::PrepareRilCmdStruct(BYTE* pBuffer, RILSIMTOOLKITCMD** pRilCmd, DWORD dwType) {
  memset(pBuffer, 0, SIMTK_MAX_LENGTH);

  *pRilCmd = (RILSIMTOOLKITCMD*)pBuffer;

  (*pRilCmd)->dwParams         =  RIL_PARAM_SIMTKIT_CMD_TYPE            |
                                  RIL_PARAM_SIMTKIT_CMD_DETAILS_OFFSET  |
                                  RIL_PARAM_SIMTKIT_CMD_DETAILS_SIZE;
  (*pRilCmd)->dwType           =  dwType;
  (*pRilCmd)->cbSize           =  ROUNDTODWORD(sizeof(RILSIMTOOLKITCMD));
  (*pRilCmd)->dwDetailsOffset  =  ROUNDTODWORD(sizeof(RILSIMTOOLKITCMD));

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Prepare and initialize the Sim-Toolkit command structure in case of an error.
//
// Params:
//  pRilCmd: Pointer to the Simtoolkit command structure
//  dwError: The error to be reported
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::PrepareRilCmdError(RILSIMTOOLKITCMD* pRilCmd, DWORD dwError) {
  pRilCmd->dwParams        |=    RIL_PARAM_SIMTKIT_CMD_ERROR;
  pRilCmd->dwParams        &=  ~(RIL_PARAM_SIMTKIT_CMD_DETAILS_OFFSET | RIL_PARAM_SIMTKIT_CMD_DETAILS_SIZE);
  pRilCmd->cbSize           =  sizeof(RILSIMTOOLKITCMD);
  pRilCmd->dwDetailsOffset  =  0;
  pRilCmd->dwError          =  dwError;

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Create and send the blob corresponding to the Sim-Toolkit command.
//
// Params:
//  dwNotificationCode: The blob notification code
//  pBlob             : The storage for the blob (out)
//  cbBlob            : The size of the blob (out)
//  pData             : The SAT command to be sent
//  dwSize            : The size of the SAT command
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::HandleBlob(DWORD dwNotificationCode, void*& pBlob, UINT& cbBlob, BYTE* pData, DWORD dwSize) {
  // Allocate the blob
  cbBlob = dwSize;
  pBlob = AllocBlob(cbBlob);
  if (!pBlob) {
    cbBlob = 0;
    return FALSE;
  }

  // Store notify data
  memcpy(pBlob, pData, cbBlob);

  // Trace blob data
  TraceBlob((BYTE*)pBlob, cbBlob);

  // Notify the SIM manager of the SAT command
  return m_pRilDevice->BroadcastRealBlobNotification(dwNotificationCode, pBlob, cbBlob);
}

